package com.wanghua.spring.test.process;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;

/*
* Process 创建的子进程没有自己的终端或控制台。它的所有标准 io（即 stdin，stdout，stderr）操作都将通过三个流
* (getOutputStream()，getInputStream()，getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。
* 因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小，如果读写子进程的输出流或输入流迅速出现失败，则可能导致子进程阻塞，甚至产生死锁。
* 在对getOutputStream()，getInputStream()，getErrorStream()的描述中，有个注意事项：对其输出流和错误流进行缓冲是一个好主意！嗯，好抽象啊！
* 问题正在于此，Process.getInputStream()和Process.getErrorStream()分别返回Process的标准输出流和错误流，两个流如果处理不当，
* 其缓冲区不能被及时清除而被塞满，则进程被阻塞，即使调用Process.destory()也未必能销毁被阻塞的子进程。
*
* 如果尝试同步获取Process的输出流和错误流进行处理，未必有效，顺序执行过程中，输出流和错误流常常不能得到及时处理。解决方案有两个。
* 方案一：并发获取Process的输出流和错误流。
* 通过启动两个线程来并发地读取和处理输出流和错误流：
* */
public class ProcessExecutor {
    private Process p;
    private List<String> outputList;
    private List<String> errorOutputList;

    public ProcessExecutor(Process p) throws IOException {
        if (null == p) {
            throw new IOException("the provided Process is null");
        }
        this.p = p;
    }

    public List<String> getOutputList() {
        return this.outputList;
    }

    public List<String> getErrorOutputList() {
        return this.errorOutputList;
    }

    public int execute(Charset charset) throws Exception {
        int rs = 0;
        ProcessOutputThread outputThread = new ProcessOutputThread(this.p.getInputStream(),charset);
        ProcessOutputThread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream(),charset);
        outputThread.start();
        errorOutputThread.start();
        rs = p.waitFor();
        outputThread.join();
        errorOutputThread.join();
        this.outputList = outputThread.getOutputList();
        this.errorOutputList = errorOutputThread.getOutputList();
        return rs;
    }

    public static void main(String[] args) {
        try {
            //如果考虑用cmd执行多条语句，应该改用bat，且bat中不要用pause，程序会被阻塞的。
            Runtime run = Runtime.getRuntime();
            Process process = run.exec("D:\\wang.h\\excelDemo\\src\\process\\a.bat");

            ProcessExecutor pe = new ProcessExecutor(process);
            pe.execute(Charset.forName("gb2312"));
            List<String> outputList = pe.getOutputList();
            List<String> errorOutputList = pe.getErrorOutputList();
            System.out.println("已执行完成");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
